﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GGEditor.API.Editors;
using System.IO;

namespace GGEditor.API.Samples.TileEditor
{
    public partial class View : UserControl, IEditorView
    {
        private const int horizontalTiles = 20;
        private const int verticalTiles = 20;
        private byte[,] tiles;
        private ITileset tileset;

        private bool rightDown = false;

        protected float Dx
        {
            get { return Width / (float)horizontalTiles; }
        }

        protected float Dy
        {
            get { return Height / (float)verticalTiles; }
        }

        public View()
        {
            InitializeComponent();

            //tiles = new byte[horizontalTiles, verticalTiles];
            //tileset = new BasicColorTileset();
			tiles = initMap;
			tileset = new DungeonTileset("..\\..\\..\\..\\config\\Samples\\DungeonTileset");

			//for (int y = 0; y < verticalTiles; y++)
			//	for (int x = 0; x < horizontalTiles; x++)
			//		tiles[x, y] = tileset.GetDefaultTile();

            SetStyle(ControlStyles.UserPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.DoubleBuffer, true);
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {

        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            using (Brush bg = new SolidBrush(BackColor))
                g.FillRectangle(bg, ClientRectangle);

			for (int x = 0; x < horizontalTiles; x++)
				for (int y = 0; y < verticalTiles; y++)
                    tileset.DrawTile(g, x * Dx, y * Dy, Dx, Dy, tiles[y, x]);

            for (int y = 0; y < verticalTiles; y++)
                g.DrawLine(Pens.White, 0, y * Dy, Width, y * Dy);

            for (int x = 0; x < horizontalTiles; x++)
                g.DrawLine(Pens.White, x * Dx, 0, x * Dx, Height);
        }

        #region IEditorView Members

        public Control Control
        {
            get { return this; }
        }

        public void SubscribeTo(IEditorModel model)
        {
            model.ModelChanged += OnModelChanged;
        }

        public void UnsubscribeFrom(IEditorModel model)
        {
            model.ModelChanged -= OnModelChanged;
        }

        private void OnModelChanged(IEditorModel model)
        {
            Invalidate();
        }

        #endregion

        private void EditorView_MouseMove(object sender, MouseEventArgs e)
        {
            if (rightDown)
            {
                int x = (int)(e.X / Dx);
                int y = (int)(e.Y / Dy);
                if(x >= 0 && x < horizontalTiles && y >= 0 && y < horizontalTiles )
                    tiles[y, x] = tileset.GetDefaultTile();
            }

            Invalidate();
        }

        private void EditorView_MouseDown(object sender, MouseEventArgs e)
        {
            

            int x = (int)(e.X / Dx);
            int y = (int)(e.Y / Dy);

            if (x >= 0 && x < tiles.GetLength(0) && y >= 0 && y < tiles.GetLength(1))
            {
                if (e.Button == MouseButtons.Left)
                {
                    //TODO This should be handled by the tool. This is basically a hard-coded "cycle tool".
                    tiles[y, x] += 1;
                    if(tiles[y, x] > tileset.GetEnd())
                        tiles[y, x] = tileset.GetStart();
                }
                else if (e.Button == MouseButtons.Right)
                {
                    rightDown = true;
                    tiles[y, x] = tileset.GetDefaultTile();
                }
            }

            Invalidate();            
        }

        private void EditorView_MouseUp(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Right)
                rightDown = false;
        }

        private void EditorView_MouseLeave(object sender, EventArgs e)
        {
            
        }

        private void EditorView_KeyUp(object sender, KeyEventArgs e)
        {

        }

		private byte[,] initMap = {{15,4,4,4,4,4,4,4,4,4,4,4,14,0,0,0,0,15,4,14},
										{1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1},
										{1,0,15,14,0,15,4,4,4,4,14,0,1,0,0,0,0,1,0,1},
										{1,0,1,1,0,1,0,0,0,0,1,0,1,0,0,15,4,13,0,1},
										{1,0,1,1,0,1,0,0,0,15,13,0,1,0,0,1,0,0,0,1},
										{1,0,12,13,0,12,4,4,4,13,0,0,12,4,4,11,5,0,0,1},
										{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
										{1,0,15,14,0,15,4,4,4,14,0,0,15,4,4,14,0,0,0,1},
										{1,0,12,13,0,12,4,4,4,9,0,0,1,0,0,12,14,0,0,1},
										{1,0,0,0,0,0,0,0,0,1,0,15,13,0,0,0,1,0,0,1},
										{1,0,15,14,0,15,4,14,0,1,0,1,0,0,0,0,1,0,0,1},
										{1,0,12,13,0,12,4,13,0,2,0,12,4,4,4,4,13,0,0,1},
										{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
										{1,0,15,14,0,6,4,4,4,4,4,10,4,14,0,15,4,14,0,1},
										{1,0,12,13,0,0,0,0,0,0,0,12,4,13,0,1,0,1,0,1},
										{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1},
										{1,0,15,14,0,15,4,4,4,14,0,15,4,14,0,1,0,1,0,1},
										{1,0,8,13,0,12,4,4,4,13,0,12,4,13,0,12,4,13,0,1},
										{1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
										{12,4,11,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,13}};

		private byte[,] initMap2 = {{15,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,14},
									{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
									{1,0,15,4,4,4,4,14,0,3,0,15,4,14,0,3,0,3,0,1},
									{1,0,1,0,0,0,0,1,0,1,0,12,4,13,0,2,0,2,0,1},
									{1,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1},
									{1,0,1,0,0,0,0,1,0,0,0,6,4,5,0,0,0,0,0,1},
									{1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},
									{1,0,1,0,0,0,0,1,0,3,0,15,4,14,0,3,0,15,4,13},
									{1,0,1,0,0,0,0,12,4,9,0,1,0,1,0,1,0,1,0,0},
									{1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,1,0,8,4,14},
									{1,0,1,0,0,0,0,0,0,1,0,12,4,13,0,1,0,1,0,1},
									{1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1},
									{1,0,1,0,0,0,0,0,0,8,4,4,14,0,0,1,0,1,0,1},
									{1,0,1,0,0,0,0,0,0,8,4,4,13,0,0,2,0,2,0,1},
									{1,0,12,4,4,4,4,4,4,13,0,0,0,0,0,0,0,0,0,1},
									{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,3,0,1},
									{1,0,6,4,4,4,4,4,5,0,6,4,4,4,4,13,0,2,0,1},
									{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
									{1,0,0,0,0,0,0,0,0,0,0,0,0,0,15,14,0,0,0,1},
									{12,4,4,4,4,4,4,4,4,4,4,4,4,4,11,11,4,4,4,13}};


    }

    interface ITileset
    {
        void DrawTile(Graphics g, float x, float y, float width, float height, byte type);

        byte GetStart();
        byte GetEnd();
        byte GetDefaultTile();
    }

	class DungeonTileset : ITileset
	{
		private const byte nothing = 0;

		private IList<Bitmap> bitmaps;

		public DungeonTileset(String path)
		{
			bitmaps = new List<Bitmap>();

            Console.WriteLine("Directory root: " + Directory.GetCurrentDirectory());

            if (!Directory.Exists(path))
            {
                Console.WriteLine("File not found!");
                throw new FileNotFoundException();
            }
			string[] filePaths = Directory.GetFiles(path);
		
			foreach (String file in filePaths)
			{
				Console.WriteLine("File: " + file);
				if (file.EndsWith(".bmp"))
					bitmaps.Add(new Bitmap(file));
			}
		}

		public void DrawTile(Graphics g, float x, float y, float width, float height, byte type)
		{
			g.DrawImage(bitmaps[type], x, y, width, height);
		}

		public byte GetStart() { return 0; }
		public byte GetEnd() { return (byte)(bitmaps.Count - 1); }
		public byte GetDefaultTile() { return nothing; }
	}
    
    class BasicColorTileset : ITileset
    {
        private const byte nothing = 0;
        private const byte red = 1;
        private const byte yellow = 2;
        private const byte blue = 3;
        private const byte orange = 4;
        private const byte green = 5;
        private const byte purple = 6;

        public void DrawTile(Graphics g, float x, float y, float width, float height, byte type)
        {
            using (Brush bg = new SolidBrush(GetColor(type)))
                g.FillRectangle(bg, x, y, width, height);
        }

        public byte GetStart() { return red; }
        public byte GetEnd() { return purple; }
        public byte GetDefaultTile() { return nothing; }

        private Color GetColor(byte type)
        {
            switch (type)
            {
                case nothing:
                    return Color.Cyan;
                case red:
                    return Color.Red;
                case yellow:
                    return Color.Yellow;
                case blue:
                    return Color.Blue;
                case orange:
                    return Color.Orange;
                case green:
                    return Color.Green;
                case purple:
                    return Color.Purple;
                default:
                    return Color.White;
            }
        }
    }
}
